package ws

import (
	"context"
	"errors"
	"io/ioutil"
	"net/http"
	"strconv"

	"gitee.com/crack007/goose/gsconfig"
	"gitee.com/crack007/goose/gscore"
	"gitee.com/crack007/goose/gslog"
	"github.com/gin-gonic/gin"
)

type Server struct {
	gscore.BaseServer
	SessionBuilder  *SessionBuilder
	Engine          *gin.Engine
	SessionManager  *SessionManager
	MessageManager  *MessageManager
	websocketServer *http.Server
	handle          IWsServerHandle
	Builder         *ServerBuilder
	server          *http.Server
	port            uint16
}

func (x *Server) SetPort(port uint16) {
	x.port = port
}

func (x *Server) InjectHandle(iHandle gscore.IHandle) {
	if v, ok := iHandle.(IWsServerHandle); ok {
		x.handle = v
		return
	}

	panic("IWsServerHandle type error")
}

func (x *Server) OnBeforeInit() {
	x.handle.OnInjectServer(x)
	x.handle.OnBeforeInit()
}

func (x *Server) OnInitConfig() {
	var err error
	defer func() {
		if err != nil {
			panic("OnInitConfig err: " + err.Error())
		}
	}()

	if x.Builder.GetConfigPath() != "" {
		gsconfig.ParseConfig(x.Builder.GetConfigPath(), x.Builder.ConfigObject)
		if v, ok := x.Builder.ConfigObject.(gscore.AppConfig); ok {
			if v.Log != nil {
				gslog.DefaultLog = gslog.NewConsoleLogger(v.Log)
			}
		}
	}

	if x.Builder.GetLogDebug() {
		gslog.DefaultLog.SetLogLevel(gslog.LEVEL_DEBUG)
	}

	if x.Builder.GetLogTrace() {
		gslog.DefaultLog.SetLogLevel(gslog.LEVEL_TRACE)
	}

	x.handle.OnInitConfig()
}

func (x *Server) OnInitInject() {

}

func (x *Server) OnInitService() {
	x.handle.OnInitService()
}

func (x *Server) OnInitRouter() {
	x.handle.OnInitRouter()
}

func (x *Server) GetBuilder() gscore.IBuilder {
	return x.Builder
}

func (x *Server) OnBeforeRun() {
	x.MessageManager.init()
	x.handle.OnBeforeRun()
}

func (x *Server) OnBuild() {
	if !x.Builder.GetLogDebug() && !x.Builder.GetLogTrace() {
		gin.SetMode(gin.ReleaseMode)
		gin.DefaultWriter = ioutil.Discard
	}

	x.Engine = gin.Default()
}

func (x *Server) OnRun() {
	x.AddGracefulTask(gscore.NewGracefulTask(func(ctx context.Context) {
		url := ":" + strconv.Itoa(int(x.port))
		gslog.Warn("websocket server [%s] start, listen: %s", x.GetServerName(), url)
		err := x.handle.OnStart()
		if err != nil {
			panic(err)
		}

		x.websocketServer = &http.Server{Addr: url, Handler: x.Engine}
		err = x.websocketServer.ListenAndServe()
		if err != nil && !errors.Is(err, http.ErrServerClosed) {
			panic(err)
		}
	}))

	go func() {
		<-x.Done()
		gslog.Warn("websocket server quit [%s]", x.GetServerName())
		x.handle.OnShutdown()
		x.websocketServer.Shutdown(x.Ctx)
		x.MessageManager.Close()
	}()

	x.GracefulExit()
}
